package com.zonski.jbots.game.room;

import java.util.Hashtable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.IOException;
//import java.io.DataInputStream;

import com.zonski.jbots.engine.InputStreamFactory;
import com.zonski.jbots.engine.Entity;
import com.zonski.jbots.engine.EntityFactory;
import com.zonski.jbots.engine.Engine;
import com.zonski.jbots.engine.Room;
import com.zonski.jbots.engine.RoomFactory;
import com.zonski.jbots.engine.Rectangle;
import com.zonski.jbots.engine.entity.AbstractMind;
import com.zonski.jbots.engine.entity.MovingEntity;

import com.zonski.jbots.game.JBotsConstants;

/** 
 * Reads a room description from an ASCII file
 */
public class AsciiRoomFactory implements RoomFactory
{
    private InputStreamFactory inputStreamFactory;

    public AsciiRoomFactory(InputStreamFactory inputStreamFactory)
    {
        this.inputStreamFactory = inputStreamFactory;
    }

    public Room getRoom(String name, Engine engine) throws Exception
    {
        InputStream stream;
        stream = this.inputStreamFactory.getInputStream(name);
        //InputStreamReader reader = new InputStreamReader(stream);
        InputStream reader = stream;

        String line;
        int lineNumber = 0;
        Room room = new Room();
        EntityFactory entityFactory = engine.getEntityFactory();

        try
        {
            line = readLine(reader);
            lineNumber++;
            // read in the name of the room
            room.setName(line);

            line = readLine(reader);
            lineNumber++;
            // read in the name of the music
            if(line.length() > 0)
            {
                room.setMusic(line);
            }

            line = readLine(reader);
            lineNumber++;
            // read in the tile size
            int tileSize = Integer.parseInt(line);
            room.setTileSize(tileSize);

            // read in the number of tiles across
            line = readLine(reader);
            lineNumber++;
            int tilesAcross = Integer.parseInt(line);
            // read in the number of tiles down
            line = readLine(reader);
            lineNumber++;
            int tilesDown = Integer.parseInt(line);

            // add in the walls
            int width = tilesAcross * tileSize;
            int height = tilesDown * tileSize;
            Entity edge;
            Rectangle r;

            edge = entityFactory.createEntity(JBotsConstants.EDGE);
            r = edge.bounds;
            r.setLocation(0, -1, width, 1);
            room.addEntity(edge);
        
            edge = entityFactory.createEntity(JBotsConstants.EDGE);
            r = edge.bounds;
            r.setLocation(-1, 0, 1, height);
            room.addEntity(edge);

            edge = entityFactory.createEntity(JBotsConstants.EDGE);
            r = edge.bounds;
            r.setLocation(0, height, width, 1);
            room.addEntity(edge);

            edge = entityFactory.createEntity(JBotsConstants.EDGE);
            r = edge.bounds;
            r.setLocation(width, 0, 1, height);
            room.addEntity(edge);

            int[][] tiles = new int[tilesDown][tilesAcross];
            // read in the tile types
            for(int i=0; i<tilesDown; i++)
            {
                line = readLine(reader);
                lineNumber++;

                for(int j=0; j<line.length(); j++)
                {
                    char c = line.charAt(j);
                    int tile = ((int)c) - ((int)'A');
                    tiles[i][j] = tile;
                }
            }
            room.setTiles(tiles);

            line = readLine(reader);
            lineNumber++;
            // read in the entities
            while(line!= null)
            {
                // read in the reference to the type
                String mindName;
                String entityTypeName;
                int index = line.indexOf(',');
                if(index >= 0)
                {
                    entityTypeName = line.substring(0, index);
                    mindName = line.substring(index+1);
                }else{
                    entityTypeName = line.trim();
                    mindName = null;
                }
                Entity entity = entityFactory.createEntity(entityTypeName);
                // player minds
                if(mindName != null)
                {
                    AbstractMind mind = (AbstractMind)engine.getMind(mindName);
                    ((MovingEntity)entity).setMind(mind);
                    mind.setEntity(entity);
                }

                // read in the position
                line = readLine(reader);
                lineNumber++;
                int x = Integer.parseInt(line);
                line = readLine(reader);
                lineNumber++;
                int y = Integer.parseInt(line);
                r = entity.bounds;
                r.setLocation(x, y);

                // layer id
                line = readLine(reader);
                lineNumber++;
                int layerId = Integer.parseInt(line);
                entity.layerId = layerId;

                room.addEntity(entity);

                // skip the blank
                line = readLine(reader);
                lineNumber++;

                if(line != null)
                {
                    line = readLine(reader);
                    lineNumber++;
                }
            }
            return room;
        }catch(Exception ex){
            throw new Exception("error at "+lineNumber+" in room file "+name+
                    " : "+ex.toString());
        }finally{
            if(stream != null)
            {
                stream.close();
            }
        }

    }

    /*
    private String readLine(Reader reader)
        throws IOException
    {
        int read = reader.read();
        if(read == -1)
        {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        while(read != ((int)'\n') && read >= 0)
        {
            if(read != ((int)'\r'))
            {
                sb.append((char)read);
            }
            read = reader.read();
        }
        return sb.toString();
    }
    */
    private String readLine(InputStream reader)
        throws IOException
    {
        int read = reader.read();
        if(read == -1)
        {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        while(read != ((int)'\n') && read >= 0)
        {
            if(read != ((int)'\r'))
            {
                sb.append((char)read);
            }
            read = reader.read();
        }
        return sb.toString();
    }
}
